---@class WUltiity : Object
local WUltiity = {}

function WUltiity:getItemByRate(cfg,excepttb)
  excepttb = excepttb or {}
  local cnt = 0
  while true do
    cnt = cnt + 1
    local rand = math.random()
    local forward = 0
    for i, v in pairs(cfg) do
      local last = v.rate
      if rand >= forward and rand < last + forward and not excepttb[i] then
        return i
      end
      forward = forward + last
    end
    if cnt >= 50 then --小概率事件。避免死循环
      local properties = {}
      for i, v in pairs(cfg) do
        table.insert(properties,i)
      end
      return table.random(properties)
    end
  end
end

function WUltiity:getItemByWeight(cfg,excepttb)
  excepttb = excepttb or {}
  local cnt = 0
  while true do
    cnt = cnt + 1
    local rand = math.random()
    local forward = 0
    for i, v in pairs(cfg) do
      local last = v
      if rand >= forward and rand < last + forward and not excepttb[i] then
        return i
      end
      forward = forward + last
    end
    if cnt >= 50 then --避免死循环
      local properties = {}
      for i, v in pairs(cfg) do
        table.insert(properties,i)
      end
      return table.random(properties)
    end
  end
end

function WUltiity:getItemsByWeight(num,cfg)
  local tb = {}
  while #tb < num do
    local rand = math.random()
    local forward = 0
    for i, v in pairs(cfg) do
      local last = v
      if rand >= forward and rand < last + forward then
         table.insert(tb,i)      
        break
      end
      forward = forward + last
    end
  end
  return tb
end

function WUltiity:checkCards(player,pattern,num)
  local room = player.room
  local exp = Exppattern:Parse(pattern)
  local cards = {}
  for _, cid in ipairs(room.draw_pile) do
    local card = Fk:getCardById(cid)
    if exp:match(card) then
      table.insert(cards,cid)
    end
    if #cards >= num then break end
  end
  if #cards < num then
    for _, cid in ipairs(room.discard_pile) do
      local card = Fk:getCardById(cid)
      if exp:match(card) then
        table.insert(cards,cid)
        if #cards >= num then break end
      end
    end
  end
  if #cards > 0 then
    room:obtainCard(player, cards, true, fk.ReasonJustMove)
  end  
end

function WUltiity:removeSameItems(items,recitems)
  local removeSkill = function(item)
    for i,it in ipairs(recitems) do
      if it == item then
        return i
      end
    end
  end
  
  local removepos = {}
  for i,it in ipairs(items) do
    local ret = removeSkill(it)
    if ret then
      table.insert(removepos,ret)
    end
  end

  while #removepos > 0 do
    local curpos = table.remove(removepos,1)
    table.remove(recitems,curpos)
  end
end

function WUltiity:removeSameItemsByTB(items,recitems,property)
  local removeSkill = function(item)
    for i,tb in ipairs(recitems) do
      if tb[property] == item then
        return i
      end
    end
  end
  
  local removepos = {}
  for i,it in ipairs(items) do
    local ret = removeSkill(it)
    if ret then
      table.insert(removepos,ret)
    end
  end

  while #removepos > 0 do
    local curpos = table.remove(removepos,1)
    table.remove(recitems,curpos)
  end
end

function WUltiity:getPlayerSkills(player)
  local skills = {}
  for _,s in ipairs(player.player_skills) do
    if s.frequency < Skill.Compulsory and not s.attached_equip then
      table.insert(skills,s.name)
    end
  end
  return skills
end

function WUltiity:getRandItemsByTB(rectb,num)
  local tb = {}
  for i=1,num do
    local item = self:getRandItemByTB(rectb)
    table.insert(tb,item)
  end
  return tb
end

function WUltiity:getRandItemByTB(rectb)
  return table.remove(rectb,math.random(1,#rectb))
end

--- 从已经开启的拓展包中，随机选出若干名武将。
---
--- 同名武将不会重复选取，武将数量也会返回能找到的武将
---@param num integer @ 要选出的武将数量
---@param generalPool? string[] @ 选择的范围，默认是已经启用的所有武将的武将名
---@param except? string[] @ 特别要排除掉的武将名列表，默认是空表
---@param filter? fun(g: General): boolean? @ 可选参数，若这个函数返回true的话这个武将被排除在外
---@return General[] @ 随机选出的武将列表
function WUltiity.getGenerals(num, generalPool, except, filter)
  if filter then
    assert(type(filter) == "function")
  end

  generalPool = generalPool or table.map(Fk:getAllGenerals(), Util.NameMapper)
  except = except or {}
  for _, g in ipairs(Fk.packages["test_p_0"].generals) do
    table.insert(except, g.name)
  end

  local availableGenerals = {}
  for _, gn in pairs(generalPool) do
    local general = Fk.generals[gn]
    if not table.contains(except, general.name) and not (filter and filter(general)) then
      if (not general.hidden and not general.total_hidden) and
        #table.filter(availableGenerals, function(g)
        return g.trueName == general.trueName
      end) == 0 then
        table.insert(availableGenerals, general)
      end
    end
  end
  table.shuffle(availableGenerals)
  return table.slice(availableGenerals, 1, num + 1)
end


return WUltiity